/*
 * H264MediaSubsession.cpp
 *
 *  Created on: 2015年11月27日
 *      Author: terry
 */

#include "H264MediaSubsession.h"
#include "H264FramedSource.h"
#include "H264VideoStreamDiscreteFramer.hh"
#include "H264VideoRTPSink.hh"
#include "TStringUtil.h"
#include "H264PropParser.h"
#include "SpsParser.h"
#include "Base64.h"
#include "CasterChannelTable.h"
#include "Base64.hh"

#include "StopWatch.h"
#include "CLog.h"
#include "GroupsockHelper.hh"

namespace av
{

H264MediaSubsession::H264MediaSubsession(UsageEnvironment& env, portNumBits initPort, MediaSourcePtr mediaSource, const std::string& entry):
		OnDemandServerMediaSubsession(env, false, initPort),
		m_mediaSource(mediaSource),
		m_entry(entry)
{
}

H264MediaSubsession::~H264MediaSubsession()
{
}

#pragma warning(disable:4996)

char const* H264MediaSubsession::sdpLines()
{
    if (fSDPLines != NULL)
    {
        return fSDPLines;
    }

    //return OnDemandServerMediaSubsession::sdpLines();
    MediaFormat fmt;
    m_mediaSource->getMediaFormat(fmt);

    unsigned estBitrate = fmt.m_bitrate > 0 ? fmt.m_bitrate : 500;
    char const* mediaType = "video";
    unsigned char rtpPayloadType = 96;
    AddressString ipAddressStr(fServerAddressForSDP);
    const char* rtpmapLine = "a=rtpmap:96 H264/90000\r\n";
    char const* rtcpmuxLine = "";
    char const* rangeLine = rangeSDPLine();

    std::string fmtp = getFmtp(rtpPayloadType, fmt);

	char const* const sdpFmt =
		"m=%s %u RTP/AVP %d\r\n"
		"c=IN IP4 %s\r\n"
		"b=AS:%u\r\n"
        //"a=recvonly\r\n"
		"%s"
		"%s"
		"%s"
		"%s"
		"a=control:%s\r\n";
	unsigned sdpFmtSize = strlen(sdpFmt)
		+ strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */
		+ strlen(ipAddressStr.val())
		+ 20 /* max int len */
		+ strlen(rtpmapLine)
		+ strlen(rtcpmuxLine)
		+ strlen(rangeLine)
		+ fmtp.size()
		+ strlen(trackId());
	char* sdpLines = new char[sdpFmtSize];
	sprintf(sdpLines, sdpFmt,
		mediaType, // m= <media>
		fPortNumForSDP, // m= <port>
		rtpPayloadType, // m= <fmt list>
		ipAddressStr.val(), // c= address
		estBitrate, // b=AS:<bandwidth>
		rtpmapLine, // a=rtpmap:... (if present)
		rtcpmuxLine, // a=rtcp-mux:... (if present)
		rangeLine, // a=range:... (if present)
		fmtp.c_str(), // optional extra SDP line
		trackId()); // a=control:<track-id>
	delete[] (char*)rangeLine;

	fSDPLines = strDup(sdpLines);
	delete[] sdpLines;

    return fSDPLines;
}

FramedSource* H264MediaSubsession::createNewStreamSource(unsigned clientSessionId,
			          unsigned& estBitrate)
{
    comn::StopWatch watch;

	MediaSourcePtr mediaSource = CasterChannelTable::instance().findWithName(m_entry);
	if (!mediaSource)
	{
		mediaSource = m_mediaSource;
	}

	MediaFormat fmt;
	mediaSource->getMediaFormat(fmt);

	estBitrate = fmt.m_bitrate/1000;

	H264FramedSource* pSource = new H264FramedSource(envir(), mediaSource, fmt, fmt.m_clockRate);

	mediaSource->forceKeyFrame();

	FramedSource* src = H264VideoStreamDiscreteFramer::createNew(envir(), pSource);

    if (watch.elapse() > 50)
    {
        CLog::warning("H264MediaSubsession::createNewStreamSource consume too much time. %d\n", watch.elapse());
    }

    return src;
}

  // "estBitrate" is the stream's estimated bitrate, in kbps
RTPSink* H264MediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,
		        unsigned char rtpPayloadTypeIfDynamic,
		        FramedSource* inputSource)
{
	setSendBufferTo(envir(), rtpGroupsock->socketNum(), 1024 * 1024 * 1);
	//unsigned int sendSize = getSendBufferSize(envir(), rtpGroupsock->socketNum());

	OutPacketBuffer::increaseMaxSizeTo(1024 * 1024);
    
    H264VideoRTPSink* sink = H264VideoRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic);
    //sink->setPacketSizes(1000, 1300);
    //sink->enableRTCPReports() = false;

	return sink; 
}

void H264MediaSubsession::setStreamSourceScale(FramedSource* inputSource, float scale)
{

}

void H264MediaSubsession::closeStreamSource(FramedSource* inputSource)
{

    OnDemandServerMediaSubsession::closeStreamSource(inputSource);
}

std::string H264MediaSubsession::getFmtp(int pt, const MediaFormat& fmt)
{
    std::string line;
    line = comn::StringUtil::format("a=fmtp:%d", pt);
    
    int profile = fmt.m_profile;
    int level = 20;
    std::string sprop;
    
    if (fmt.m_videoProp.size() > 0)
    {
        std::string sps;
        std::string pps;
        if (H264PropParser::splitPropSet(fmt.m_videoProp, sps, pps))
        {
            SpsParser::h264_sps_t h264_sps;
            if (SpsParser::parse((const uint8_t*)sps.c_str()+1, sps.size()-1, h264_sps))
            {
                profile = h264_sps.profile;
                level = h264_sps.level;
            }
            
            char* text = base64Encode(sps.c_str(), sps.size());
            sprop += text;
            delete[] text;

            text = base64Encode(pps.c_str(), pps.size());
            sprop += ",";
            sprop += text;
            delete[] text;
        }
    }

    line += " packetization-mode=1;";
    line += comn::StringUtil::format("profile-level-id=%02x00%02x;", profile, level);

    if (sprop.size() > 0)
    {
        line += comn::StringUtil::format("sprop-parameter-sets=%s", sprop.c_str());
    }

    line += "\r\n";
    return line;
}



} /* namespace av */
